package persistence;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import model.Conjunto;
import model.Material;
import model.MaterialPrenda;
import model.Prenda;
import model.PrendaSinTemporada;
import model.PrendaTemporada;
import model.Producto;


public class ProductoMapper {
	private static ProductoMapper instance = null;
	private PrendaSinTemporadaMapper prendaSTMapper;
	private PrendaTemporadaMapper prendaTMapper;
	private ConjuntoMapper conjuntoMapper;
	
	protected ProductoMapper() {}

	public static ProductoMapper getInstance() {
		if (instance == null) {
			instance = new ProductoMapper();
		}
		return instance;
	}
	
	protected int getProximaClaveProducto() {
		Connection con = PoolConnection.getPoolConnection().getConnection();
		int productoClave = -1;
		try {
			String query = "SELECT sequence_next_hi_value from sequences where sequence_name = ?";
			PreparedStatement ps = con.prepareStatement(query);
			ps.setString(1, "product");
			ResultSet result = ps.executeQuery();
			
			if(result.next()) {
				productoClave = result.getInt("sequence_next_hi_value");
				
				query = "UPDATE sequences set sequence_next_hi_value = ? where sequence_name = ?";
				ps = con.prepareStatement(query);
				ps.setInt(1, productoClave+1);
				ps.setString(2, "product");
				ps.execute();
			}
			
			PoolConnection.getPoolConnection().releaseConnection(con);

		} catch (SQLException e) {
			System.out.println("Mensaje Error al buscar Proxima clave de Producto: " + e.getMessage());
			System.out.println("Stack Trace al buscar Proxima clave de Producto: " + e.getStackTrace());
			PoolConnection.getPoolConnection().releaseConnection(con);
		}
		
		return productoClave;
	}
	
	protected void insertarMaterialPrenda(Connection connection, MaterialPrenda materialPrenda) throws SQLException {
			String query = "INSERT INTO material_prenda (cantidad, prenda_id, material_id) VALUES (?,?,?)";
			PreparedStatement ps = connection.prepareStatement(query);
			ps.setInt(1, materialPrenda.getCantidad());
			ps.setLong(2, materialPrenda.getPrenda().getProductoId());
			ps.setLong(3, materialPrenda.getMaterial().getMaterialId());
			ps.execute();
	}
	
	protected List<MaterialPrenda> buscarMaterialesPrenda(Connection connection, Prenda prenda) throws SQLException {
		MaterialMapper materialMapper = MaterialMapper.getInstance();
		List<MaterialPrenda> materialesPrenda = new ArrayList<MaterialPrenda>();
		
		String query = "SELECT * from material_prenda where prenda_id = ?";
		PreparedStatement ps = connection.prepareStatement(query);
		ps.setLong(1, prenda.getProductoId());
		ResultSet result = ps.executeQuery();
		
		while(result.next()) {
			Material material = materialMapper.buscar(result.getLong("material_id"));
			MaterialPrenda materialPrenda = new MaterialPrenda(result.getInt("cantidad"), material,prenda);
			materialesPrenda.add(materialPrenda);
		}
		
		return materialesPrenda;
	}


	/**
	 * Retornamos una lista con todas las prendas existentes, tanto sin temporada como con temporada.
	 * @return
	 */
	public List<Prenda> buscarPrendas() {
		prendaSTMapper = PrendaSinTemporadaMapper.getInstance();
		prendaTMapper = PrendaTemporadaMapper.getInstance();
		List<PrendaSinTemporada> prendasST = prendaSTMapper.buscarTodos();
		List<PrendaTemporada> prendasT = prendaTMapper.buscarTodos();
		
		List<Prenda> prendas = new ArrayList<Prenda>(prendasST);
		prendas.addAll(prendasT);
		
		return prendas;
	}
	
	/**
	 * Retornamos una lista con todos los productos existentes. Utilizamos esta lista para generar una factura con los productos comprados.
	 * @return List<Producto> productos, mezcla de PrendaSinTemporada, PrendaTemporada y Conjunto
	 */
	public List<Producto> buscarProductos() {
		conjuntoMapper = ConjuntoMapper.getInstance();
		
		List<Conjunto> conjuntos = conjuntoMapper.buscarTodos();
		
		List<Producto> productos =  new ArrayList<Producto>(conjuntos);
		productos.addAll(buscarPrendas());
		return productos;
	}
	
	/**
	 * Se busca un producto sin saber que tipo es. Primero buscamos PrendaSinTemporada, luego PrendaTemporada y por ultimo Conjunto.
	 * El promedio de consultas por producto es inferior a 2 ya que la mayoria de consultas son PrendaSinTemporada de "orden 1".
	 * @param productoId
	 * @return
	 */
	public Producto buscarProducto(long productoId) {
		Producto producto = null;
		producto = buscarPrenda(productoId);
		if(producto == null) {
			conjuntoMapper = ConjuntoMapper.getInstance();
			producto = conjuntoMapper.buscar(productoId);
		}
		
		return producto;
	}
	
	/**
	 * Recibimos el id de un producto que sabemos que es una prenda, debemos buscarlo entre las prendas sin temporada y las prendas con temporada
	 * @param productoId
	 * @return Prenda prenda encontrada, ya sea sin temporada o con temporada
	 */
	public Prenda buscarPrenda(long productoId){
		Prenda prenda = null;
		prendaSTMapper = PrendaSinTemporadaMapper.getInstance();
		prenda = prendaSTMapper.buscar(productoId);
		
		if(prenda == null) {
			prendaTMapper = PrendaTemporadaMapper.getInstance();
			prenda = prendaTMapper.buscar(productoId);
		}
		
		return prenda;
	}

	public void actualizarStock(Producto producto, int cantidad) {
		if(producto instanceof PrendaTemporada){
			PrendaTemporadaMapper.getInstance().actualizarStock((PrendaTemporada)producto, cantidad);
		}else if(producto instanceof PrendaSinTemporada) {
			PrendaSinTemporadaMapper.getInstance().actualizarStock((PrendaSinTemporada)producto, cantidad);
		}else if(producto instanceof Conjunto) {
			ConjuntoMapper.getInstance().actualizarStock((Conjunto)producto, cantidad);
		}
	}
	
	

}